#include "cm_dblitemanager.h"

using namespace sqlite3x;

CM_DBLiteManager::CM_DBLiteManager() 
{

}

CM_DBLiteManager::~CM_DBLiteManager() 
{

}

int CM_DBLiteManager::initialize(const wstring &path) 
{
    return 0;
}

int CM_DBLiteManager::initialize() 
{
    FILE* pFile;
    pFile = _wfopen (DEFAULT_DATABASE_NAME.c_str(), L"rb");
    if(!pFile)
    {
        try {
            sqlite3_connection con(DEFAULT_DATABASE_NAME.c_str());
            con.executenonquery(wstring(DOMAIN_SCRIPT));
            con.executenonquery(wstring(COMPUTER_SCRIPT));
            con.executenonquery(wstring(COLLECTION_SCRIPT));
            con.executenonquery(wstring(PROCESS_SCRIPT));
            con.executenonquery(wstring(SHARE_SCRIPT));
            con.executenonquery(wstring(REGISTRY_SCRIPT));
            con.executenonquery(wstring(VALUE_SCRIPT));
			con.executenonquery(wstring(DIRECTORY_SCRIPT));
			con.executenonquery(wstring(FILE_SCRIPT));
            con.close();
        }
        catch(exception &ex) {
            std::cerr << "Exception Occured: " << ex.what() << std::endl;
            return 0;
        }
    }
    
    return 1;
}

int CM_DBLiteManager::drop() {
    return 0;
}

int CM_DBLiteManager::saveDomain(ADCM_Domain& domain)
{
	//if(exist(domain))
	//{
	//	deleteComputers(domain);
	//	return 0;
	//}
	
	try
	{
		// save domain
		sqlite3_connection con(DEFAULT_DATABASE_NAME.c_str());

		sqlite3_transaction trans(con);
		{
			sqlite3_command cmd(con, "insert into domain (dc, fdnq) values(?, ?);");
			cmd.bind(1, domain.getDc().c_str());
			cmd.bind(2, domain.getFqdn().c_str());

			cmd.executenonquery();
		}
		trans.commit();
		
		//set id domain
		sqlite3_connection conSel(DEFAULT_DATABASE_NAME.c_str());
		sqlite3_command cmd(conSel, "select max(domain_id) from domain;");
		domain.setDomainID(cmd.executeint());


		
	}
	catch(exception &ex)
	{
		cerr << "Exception Occured: " << ex.what() << endl;
		return 0;
	}

    return 1;
}

int CM_DBLiteManager::getDomain(int idDomain, ADCM_Domain& domain)
{
	int COL_ID_DOMAIN = 0;
	int COL_DC_TEXT = 1;
	int COL_FDNQ_TEXT = 2;

	try
	{
		sqlite3_connection con(DEFAULT_DATABASE_NAME.c_str());

		sqlite3_command cmd(con, "select * from domain;");
		sqlite3_reader reader = cmd.executereader();

		while(reader.read())
		{
			if(reader.getint(COL_ID_DOMAIN) == idDomain)
			{
				domain.setDc(wstring(reader.getstring16(COL_DC_TEXT)));
				domain.setFqdn(wstring(reader.getstring16(COL_FDNQ_TEXT)));
				return 1;
			}
		}
	}
	catch(exception &ex)
	{
		cerr << "Exception Occured: " << ex.what() << endl;
	}
	return 0;
}


int CM_DBLiteManager::saveComputer(int domainID, ADCM_Computer& computer)
{

	//if(exist(domainID, computer))
	//{
	//	//the computer already exist and cant insert again
	//	return 0;
	//}


	try
	{
		// save computer
		sqlite3_connection con(DEFAULT_DATABASE_NAME.c_str());

		sqlite3_transaction trans(con);
		{
			sqlite3_command cmd(con, "insert into computer (domain_id, cn, os) values(?, ?, ?);");

			cmd.bind(1, domainID);
			cmd.bind(2, computer.getCn().c_str());
			cmd.bind(3, computer.getOs().c_str());
			cmd.executenonquery();
			
		}
		trans.commit();
		con.close();

		//set id computer
		sqlite3_connection conSel(DEFAULT_DATABASE_NAME.c_str());
		sqlite3_command cmd(conSel, "select max(computer_id) from computer;");

		computer.setIdComputer(cmd.executeint());

	}
	catch(exception &ex)
	{
		cerr << "Exception Occured: " << ex.what() << endl;
		return 0;
	}
    return 1;
}

int CM_DBLiteManager::getComputers(int idDomain, vector<ADCM_Computer>& computers)
{
	int COL_ID_COMPUTER = 0;
	int COL_ID_DOMAIN = 1;
	int COL_OS_TEXT = 2;
	int COL_CN_TEXT = 3;

	try
	{
		sqlite3_connection con(DEFAULT_DATABASE_NAME.c_str());

		sqlite3_command cmd(con, "select * from computer;");
		sqlite3_reader reader = cmd.executereader();

		ADCM_Computer* current = NULL;

		while(reader.read())
		{
			if(reader.getint(COL_ID_DOMAIN) == idDomain)
			{
				current = new ADCM_Computer(
					wstring(reader.getstring16(COL_CN_TEXT))
					, 
					wstring(reader.getstring16(COL_OS_TEXT))
				);

				current->setIdComputer(reader.getint(COL_ID_COMPUTER));

				// possible error with copy constructor 
				computers.push_back(*current);

				if(current != NULL)
				{
					delete current;
					current = NULL;
				}

			}
		}
	}
	catch(exception &ex)
	{
		cerr << "Exception Occured: " << ex.what() << endl;
		return 0;
	}
	
	return 1;
}

int CM_DBLiteManager::getComputers(wstring fqdn, vector<ADCM_Computer>& computers )
{
	int COL_ID_DOMAIN = 0;
	int COL_DC_TEXT = 1;
	int COL_FDNQ_TEXT = 2;

	// 0 (zero) means that domain not exist, otherwise represent the id off database
	int idDomain = 0;

	try
	{
		sqlite3_connection con;
		con.open(DEFAULT_DATABASE_NAME.c_str());
		sqlite3_command cmd(con, "select * from domain;");
		sqlite3_reader reader = cmd.executereader();

		//wstring mycad;

		int resp = 0;
		wstring mycad = L"";
		while(reader.read())
		{
			mycad.erase();
			mycad.append(reader.getstring16(COL_FDNQ_TEXT));
			if(fqdn.compare(mycad) == 0)
			{
				idDomain = reader.getint(COL_ID_DOMAIN);
			}
			if(idDomain != 0)
				break;
		}

		if(idDomain == 0)
		{
			
			reader.reset();
			reader.close();
			return 0;
		}

	}
	catch(exception &ex)
	{
		cerr << "Exception Occured: " << ex.what() << endl;
	}

	return getComputers(idDomain, computers);
}

int CM_DBLiteManager::saveResultCollection(int computerId, CM_ResultCollection& collection)
{
    CM_CollectionItem collItem;
    int collectionId = collItem.saveCollectionTime(computerId);
    
    CM_ShareItem shareItem;
    shareItem.saveShares(collectionId, collection.getShares());

    CM_RegistryItem regItem;
    regItem.saveRegistries(collectionId, collection.getRegistries());

    CM_FileDirectoryItem fileDirItem;
    fileDirItem.saveFileDirectory(collectionId, collection.getFileDirs());

    CM_ProcessItem processItem;
    processItem.saveProcess(collectionId, collection.getProcesses());

    return 1;
}

int CM_DBLiteManager::getLastCollection(int computerId, CM_ResultCollection& collection) 
{
    CM_CollectionItem collItem;
    int collectionId = collItem.getCollectionLastId(computerId);

    CM_ShareItem shareItem;
    shareItem.getShares(collectionId, collection.getShares());

    CM_RegistryItem regItem;
    regItem.getRegistries(collectionId, collection.getRegistries());

    CM_FileDirectoryItem fileDirItem;
    fileDirItem.getFileDirectory(collectionId, collection.getFileDirs());

    CM_ProcessItem processItem;
    processItem.getProcess(collectionId, collection.getProcesses());

    return 1;
}

int CM_DBLiteManager::getBeforeLastCollection(int computerId, CM_ResultCollection& collection) 
{
    CM_CollectionItem collItem;
    int collectionId = collItem.getCollectionBeforeLastId(computerId);

    CM_ShareItem shareItem;
    shareItem.getShares(collectionId, collection.getShares());

    CM_RegistryItem regItem;
    regItem.getRegistries(collectionId, collection.getRegistries());

    CM_FileDirectoryItem fileDirItem;
    fileDirItem.getFileDirectory(collectionId, collection.getFileDirs());

    CM_ProcessItem processItem;
    processItem.getProcess(collectionId, collection.getProcesses());

    return 1;
}

bool CM_DBLiteManager::exist(int idDomain, ADCM_Computer& computer)
{	
	bool res = false;
	int COL_ID_DOMAIN = 1;
	int COL_CN_TEXT = 3;

	try
	{
		sqlite3_connection con(DEFAULT_DATABASE_NAME.c_str());

		sqlite3_command cmd(con, "select * from computer;");
		sqlite3_reader reader = cmd.executereader();

		wstring mystr = L"";	
		while(reader.read())
		{
			mystr.erase();
			mystr.append(reader.getstring16(COL_CN_TEXT));

			// if the computer already exist in database
			if( reader.getint(COL_ID_DOMAIN) == idDomain 
				&& 
				mystr.compare( computer.getCn().c_str() ) == 0
				)
			{
				res = true;
				break;
			}
		}		
	}

	catch(exception &ex)
	{
		cerr << "Exception Occured: " << ex.what() << endl;
		return 0;
	}

	return res;
}

bool CM_DBLiteManager::exist(ADCM_Domain& domain)
{	
	bool res = false;
	int COL_ID_DOMAIN = 0;
	int COL_DC_TEXT = 1;
	int COL_FDNQ_TEXT = 2;

	try
	{
		sqlite3_connection con(DEFAULT_DATABASE_NAME.c_str());

		sqlite3_command cmd(con, "select * from domain;");
		sqlite3_reader reader = cmd.executereader();

		wstring mystr = L"";	
		while(reader.read())
		{
			mystr.erase();
			mystr.append(reader.getstring16(COL_FDNQ_TEXT));

			// if the domain already exist in database
			if( mystr.compare( domain.getFqdn().c_str() ) == 0 )
			{
				domain.setDc(reader.getstring16(COL_DC_TEXT));
				domain.setDomainID(reader.getint(COL_ID_DOMAIN));
				res = true;
				break;
			}
		}		
	}

	catch(exception &ex)
	{
		cerr << "Exception Occured: " << ex.what() << endl;
		return 0;
	}

	return res;
}

void CM_DBLiteManager::deleteComputers(ADCM_Domain& domain)
{
	try
	{
		// save computer
		sqlite3_connection con(DEFAULT_DATABASE_NAME.c_str());

		sqlite3_transaction trans(con);
		{
			sqlite3_command cmd(con, "delete from computer where domain_id == ?;");

			cmd.bind(1, domain.getDomainID());
			cmd.executenonquery();
			
		}
		trans.commit();
		con.close();
	}
	catch(exception &ex)
	{
		cerr << "Exception Occured: " << ex.what() << endl;
	}
}